/*================================================================
 *   Copyright (C) 2021 All rights reserved.
 *   
 *   文件名称：fiber.h
 *   创 建 者：汉森伯逸
 *   创建日期：2021/3/18
 *   描    述：
 *
 *================================================================*/
#pragma once

#include <memory>
#include <ucontext.h>
#include <functional>
#include "thread.h"
#include "util/dump.h"
#include "util/util.h"

namespace hsby{

/**
 * @brief 协程
 */
class Fiber : public std::enable_shared_from_this<Fiber>
            , public BaseDump{

public:
    typedef std::shared_ptr<Fiber> Ptr;

    enum State {
        INIT,       // 初始化
        READY,      // 就绪
        EXEC,       // 执行
        HOLD,       // 挂起
        TERM,       // 结束
        EXCEPT      // 出错
    };

private:
    /**
     * @brief 禁止用户使用默认构造函数, 它将当前为设置线程协程
     */
    Fiber();
public:
    Fiber(std::function<void ()> cb, size_t stackSize = 0);

    ~Fiber();

    /**
     * @brief 重置协程正文，并重置状态
     */
    void Reset(std::function<void()> cb);

public:
    void Dump(std::ostream &os) const override;

public:
    /**
     * @brief 取得当前上下文id
     */
    uint64_t GetId();

     /**
      * @brief 取得当前上下文状态
      */
    State GetState();

    /**
     * @brief 设置当前上下文状态
     */
    void SetState(State st);

    /**
     * @brief 从工作线程切换到当前协程执行
     */
    void SwapIn();

    /**
     * @brief 切换回到工作协程
     */
    void SwapOut();

public:
    /**
     * @brief 设置当前协程
     */
    static void SetCurrentFiber(Fiber::Ptr fiber);

    /**
     * @brief 返回当前协程
     */
    static Fiber::Ptr GetCurrentFiber();

    /**
     * @brief 取得当前协程ID
     */
    static uint64_t GetCurrentFiberId();

    /**
     * @brief 协程切换到后台，并设置为Ready状态
     */
    static void YieldToReady();

    /**
     * @brief 协程切换到后台，并设置为Ready状态
     */
    static void YieldToHold();

    /**
     * @brief 协程总数
     */
    static uint64_t GetFiberCount();

    /**
     * @brief 协程入口
     */
    static void OnFiber();

private:
    /// 协程id
    uint64_t id_ = 0;
    /// 线程id
    uint64_t thread_id_ = 0;
    /// 协程栈大小
    uint32_t stack_size_ = 0;
    /// 协程状态
    State state_ = INIT;
    /// 协程上下文
    ucontext_t context_;
    /// 协程栈
    void* stack_ = nullptr;
    /// 协程回调
    std::function<void()> cb_;

public:
    FUNCTION_BUILDER_VAR_GETTER(ThreadId, thread_id_);
};

}